#ifndef __MY_LOGGER_H__
#define __MY_LOGGER_H__

#include "LogLevel.hpp"
#include "LogFormatter.hpp"
#include "LogMessage.hpp"
#include "LogSink.hpp"
#include "AsyncLooper.hpp"
#include <string>
#include <vector>
#include <mutex>
#include <cassert>
#include <unordered_map>
#include <stdarg.h>

namespace LzcLog
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(const std::string &logger_name,
               LogLevel::Value min_level,
               LogFormatter::ptr formatter,
               std::vector<LogSink::ptr> &sinks)
            : _logger_name(logger_name)
            , _formatter(formatter)
            , _sinks(sinks)
            , _min_level(min_level)
        {}
        // 基类析构函数设为虚函数后，子类析构函数会自动参与多态，
        // 确保通过基类指针销毁子类对象时，析构函数的调用符合 “实际对象类型”。
        virtual ~Logger() = default;
        const std::string& GetName() { return _logger_name; } 
        LogLevel::Value GetMinLevel() const { return _min_level; }
        
        void DEBUG(const std::string& file_name, size_t line_num, const char* fmt, ...){
            if(LogLevel::Value::DEBUG >= _min_level){
                // 1. 构建日志消息
                va_list ap;
                va_start(ap, fmt);   
                char* str;
                vasprintf(&str, fmt, ap);
                LogMessage message(LogLevel::Value::DEBUG, _logger_name, file_name, line_num, str);
                va_end(ap);
                free(str);
                // 2. 格式化日志消息
                std::string data = _formatter->format(message);
                // 3. 日志消息落地
                Log(data.data(), data.size());
            }
        }
        void INFO(const std::string& file_name, size_t line_num, const char* fmt, ...){
            if(LogLevel::Value::INFO >= _min_level){
                // 1. 构建日志消息
                va_list ap;
                va_start(ap, fmt);   
                char* str;
                vasprintf(&str, fmt, ap);
                LogMessage message(LogLevel::Value::INFO, _logger_name, file_name, line_num, str);
                va_end(ap);
                free(str);
                // 2. 格式化日志消息
                std::string data(_formatter->format(message));
                // 3. 日志消息落地
                Log(data.data(), data.size());
            }
        }
        void WARNING(const std::string& file_name, size_t line_num, const char* fmt, ...){
            if(LogLevel::Value::WARNING >= _min_level){
                // 1. 构建日志消息
                va_list ap;
                va_start(ap, fmt);   
                char* str;
                vasprintf(&str, fmt, ap);
                LogMessage message(LogLevel::Value::WARNING, _logger_name, file_name, line_num, str);
                va_end(ap);
                free(str);
                // 2. 格式化日志消息
                std::string data(_formatter->format(message));
                // 3. 日志消息落地
                Log(data.data(), data.size());
            }
        }
        void ERROR(const std::string& file_name, size_t line_num, const char* fmt, ...){
            if(LogLevel::Value::ERROR >= _min_level){
                // 1. 构建日志消息
                va_list ap;
                va_start(ap, fmt);   
                char* str;
                vasprintf(&str, fmt, ap);
                LogMessage message(LogLevel::Value::ERROR, _logger_name, file_name, line_num, str);
                va_end(ap);
                free(str);
                // 2. 格式化日志消息
                std::string data(_formatter->format(message));
                // 3. 日志消息落地
                Log(data.data(), data.size());
            }
        }
        void FATAL(const std::string& file_name, size_t line_num, const char* fmt, ...){
            if(LogLevel::Value::FATAL >= _min_level){
                // 1. 构建日志消息
                va_list ap;
                va_start(ap, fmt);   
                char* str;
                vasprintf(&str, fmt, ap);
                LogMessage message(LogLevel::Value::FATAL, _logger_name, file_name, line_num, str);
                va_end(ap);
                free(str);
                // 2. 格式化日志消息
                std::string data(_formatter->format(message));
                // 3. 日志消息落地
                Log(data.data(), data.size());
            }
        }

        virtual void Log(const char* data, size_t len) = 0;
    protected:
        std::string _logger_name;
        LogLevel::Value _min_level;
        LogFormatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
        std::mutex _mutex;
    };

    enum class LoggerType
    {
        LOGGER_SYNC, // 同步日志器
        LOGGER_ASYNC // 异步日志器
    };

    class LoggerBuilder
    {
    public:
        LoggerBuilder()
        :_logger_type(LoggerType::LOGGER_SYNC) // 默认同步
        ,_min_level(LogLevel::Value::DEBUG) // 默认 >= DEBUG
        ,_async_type(AsyncType::ASYNC_SAFE) // 异步时，默认固定长度
        {}
        virtual ~LoggerBuilder() = default;

        void BuildLoggerType(LoggerType logger_type) { _logger_type = logger_type; }
        void BuildLoggerName(const std::string& logger_name) { _logger_name = logger_name; }
        void BuildLoggerMinLevel(LogLevel::Value min_level) { _min_level = min_level; }
        void BuildLoggerFormatter(const std::string& pattern = default_pattern) {
            _formatter = std::make_shared<LogFormatter>(pattern);
        }
        void BuildUnSafeAsync() {_async_type = AsyncType::ASYNC_UNSAFE; }
        template<typename SinkType, typename ...Args>
        void BuildLoggerSink(Args&& ...args) {
            _sinks.push_back(SinkFactory::CreateSink<SinkType>(std::forward<Args>(args)...));
        }
        virtual Logger::ptr Build() = 0; // 分局部和全局
    protected:
        AsyncType _async_type;
        LoggerType _logger_type;
        std::string _logger_name;
        LogLevel::Value _min_level;
        LogFormatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name,
               LogLevel::Value min_level,
               LogFormatter::ptr formatter,
               std::vector<LogSink::ptr> &sinks)
            :Logger(logger_name, min_level, formatter, sinks)
        {}
        void Log(const char* data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(!_sinks.empty())
            {
                for(auto& sink : _sinks)
                {
                    sink->Log(data, len);
                }
            }
        }
    };

    class AsyncLogger : public Logger
    {
    public:
        AsyncLogger(const std::string &logger_name,
            LogLevel::Value min_level,
            LogFormatter::ptr formatter,
            std::vector<LogSink::ptr> &sinks,
            AsyncType async_type)
            :Logger(logger_name, min_level, formatter, sinks)
            ,_async_looper(std::make_shared<AsyncLooper>(async_type, [this](Buffer& buffer){
                this->RealLog(buffer);}))
        {}
        void Log(const char* data, size_t len) override {
            _async_looper->Push(data, len);
        }
        // 实际的日志消息落地函数
        void RealLog(Buffer& buffer) {
            if(!_sinks.empty()) // 只有一个异步线程，不需要加锁
            {
                for(auto& sink : _sinks)
                {
                    sink->Log(buffer.Begin(), buffer.ReadAbleSize());
                }
            }
        }
    private:
        AsyncLooper::ptr _async_looper;
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        Logger::ptr Build() override{
            assert(!_logger_name.empty()); // 日志器名字必须要有
            if(_formatter == nullptr) BuildLoggerFormatter(); // 没有格式，采用默认格式
            if(_sinks.empty()) BuildLoggerSink<StdoutSink>(); // 没有落地方式，默认标准输出
            if(_logger_type == LoggerType::LOGGER_ASYNC)
                return std::make_shared<AsyncLogger>(_logger_name, _min_level, _formatter, _sinks, _async_type);
                
            return std::make_shared<SyncLogger>(_logger_name, _min_level, _formatter, _sinks);
        }
    };

    class LoggerManager{
    private:
        LoggerManager() {
            auto builder = std::make_unique<LocalLoggerBuilder>();
            builder->BuildLoggerName("root"); // 其他默认
            _root_logger = builder->Build();
            _loggers.emplace("root", _root_logger);
        }
        LoggerManager(const LoggerManager&) = delete;
        LoggerManager& operator=(const LoggerManager&) = delete;
    public:
        static LoggerManager& GetInstance() {
            // C++11后，局部静态成员初始化，是线程安全的
            static LoggerManager eton;
            return eton;
        }
        // 感觉加了锁的函数，之间就不能随便调用了。
        // 比如下面，HAddLogger和asLogger里面都需要加锁，
        // AddLogger里面调用HasLogger，
        // 如果在lock前面调用HasLogger，判断没有，但是抢到锁的时候，其他线程已经add了。
        // 如果在lock后面调用HasLogger，两层lock？抢到锁，又要抢锁？死锁了。
        // 可以在外部加锁。
        // 这里我就不相互调用了
        void AddLogger(const Logger::ptr& logger) {
            std::lock_guard<std::mutex> lock(_mutex);
            if(_loggers.find(logger->GetName()) == _loggers.end())
                _loggers.emplace(logger->GetName(), logger);
        }
        bool HasLogger(const std::string& name) {
            std::lock_guard<std::mutex> lock(_mutex);
            return _loggers.find(name) != _loggers.end();
        }
        Logger::ptr GetLogger(const std::string& name) {
            std::lock_guard<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it != _loggers.end())
                return it->second;
            else
                return nullptr;
        }
        Logger::ptr GetRootLogger() {
            // 不会修改_root_logger，不需要加锁
            return _root_logger;
        }
    private:
        Logger::ptr _root_logger; // 默认日志器
        std::mutex _mutex;
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };
    
    class GlobalLoggerBuilder : public LoggerBuilder {
    public:
        Logger::ptr Build() override{
            assert(!_logger_name.empty()); // 日志器名字必须要有
            if(_formatter == nullptr) BuildLoggerFormatter(); // 没有格式，采用默认格式
            if(_sinks.empty()) BuildLoggerSink<StdoutSink>(); // 没有落地方式，默认标准输出
            Logger::ptr logger;
            if(_logger_type == LoggerType::LOGGER_ASYNC)
                logger = std::make_shared<AsyncLogger>(_logger_name, _min_level, _formatter, _sinks, _async_type);
            else 
                logger = std::make_shared<SyncLogger>(_logger_name, _min_level, _formatter, _sinks);
            LoggerManager::GetInstance().AddLogger(logger);
            // C++11后，局部静态成员初始化是线程安全的(只初始化一次，底层通过初始化锁)。
            // 如果LoggerManager的构造里面，是GlobalLoggerBuilder。
            // 那么GlobalLoggerBuilder builder，Build第一次获取单例对象时(获得初始化锁)，
            // 单例对象要构造GlobalLoggerBuilder，又调用Build，又进行第二次获取单例对象，
            // 第二次发现没有完成初始化，想初始化(获取初始化锁，但是已经持有初始化锁了)，死锁了。

            return logger;
        }
    };
}

#endif